#include "SwapChain.hpp"
#include "Context.hpp"

namespace vlk
{
    SwapChain::SwapChain(int w, int h)
    {
        queryInfo(w, h);
        vk::SwapchainCreateInfoKHR createInfo;
        createInfo.setClipped(true)
                  .setImageArrayLayers(1)
                  .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
                  .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
                  .setSurface(Context::GetInstance().surface)
                  .setImageColorSpace(info.format.colorSpace)
                  .setImageExtent(info.imageExtent)
                  .setImageFormat(info.format.format)
                  .setMinImageCount(info.imageCount)
                  .setPresentMode(info.presentMode);

        auto& queueIndicates = Context::GetInstance().queueFamilyIndicates;
        if (queueIndicates.graphicQueue.value() == queueIndicates.presentQueue.value()) {
            createInfo.setQueueFamilyIndices(queueIndicates.graphicQueue.value())
                      .setImageSharingMode(vk::SharingMode::eExclusive);
        } else {
            std::array indicates = {queueIndicates.graphicQueue.value(), queueIndicates.presentQueue.value()};
            createInfo.setQueueFamilyIndices(indicates)
                      .setImageSharingMode(vk::SharingMode::eConcurrent);
        }

        /* Create swap chain */
        swapChain = Context::GetInstance().logicDevice.createSwapchainKHR(createInfo);
    }
    SwapChain::~SwapChain()
    {
        Context::GetInstance().logicDevice.destroySwapchainKHR(swapChain);
    }
    void SwapChain::queryInfo(int w, int h) {
        auto& phyDevice = Context::GetInstance().physicalDevie;
        auto& surface = Context::GetInstance().surface;
        auto formats = phyDevice.getSurfaceFormatsKHR(surface);
        info.format = formats[0];
        for(const auto& format : formats) {
            if (format.format == vk::Format::eR8G8B8A8Srgb &&
                format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
                    info.format = format;
                    break;
                }
        }

        auto capabilities = phyDevice.getSurfaceCapabilitiesKHR(surface);
        info.imageCount = std::clamp<uint32_t>(2, capabilities.minImageCount, capabilities.maxImageCount);
        info.imageExtent.width = std::clamp<uint32_t>(w, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
        info.imageExtent.height = std::clamp<uint32_t>(w, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
        info.transform = capabilities.currentTransform;

        auto presentModes = phyDevice.getSurfacePresentModesKHR(surface);
        info.presentMode = vk::PresentModeKHR::eFifo;
        for(const auto& presentMode : presentModes) {
            if (presentMode == vk::PresentModeKHR::eMailbox) {
                info.presentMode = presentMode;
            }
        }
    }
}